//==============================================================================
//
//        DArray - the dynamic array collection in the ofc-library
//
//               Copyright (C) 2003  Dick van Oudheusden
//  
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this library; if not, write to the Free
// Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//==============================================================================
// 
//  $Date: 2006-07-22 13:28:55 $ $Revision: 1.10 $
//
//==============================================================================

#include "ofc/DArray.h"


#if _INTERFACE_

#include "ofc/config.h"

// The array collection stores objects in an array that can grow. Objects
// can be accessed by an index. Due to the easy access there is no iterator.

@interface DArray : Object
{
@private
  id            *_objects;  // the stored objects
  long           _length;   // the length of the array
}
#endif


@implementation DArray

//// Constructors

//
// Initialise to an empty array
//
// @return the object
//

- (DArray *) init
{
  [self init :1];

  return self;
}

//
// Initialise to an array with an initial length
//
// @param length   the length of the array
//
// @return the object
//

- (DArray *) init :(long) length
{
  [super init];

  if (length < 1)
  {
    WARNING(DW_INVALID_ARG, "length");
    length = 1;
  }
    
  _length = length;
    
  _objects = (id *) objc_malloc(sizeof(id) * _length);
  
  {
    long i;
    
    for (i = 0; i < _length; i++)
    {
      _objects[i] = nil;
    }
  }

  return self;
}


//// Copy related methods

//
// Do a shallow copy of the array
// 
// @return the object
// 
- shallowCopy
{
  long    i;
  
  DArray *copy = [super shallowCopy];

  copy->_objects = (id *) objc_malloc(sizeof(id) * _length);
  
  for (i = 0; i < _length; i++)
  {
    copy->_objects[i] = _objects[i]; // only references
  }
  
  return copy;
}
  
//
// Deepen a copy of the array
//
// @return the object
//

- deepen
{
  long i;
  
  [super deepen];
  
  for (i = 0; i < _length; i++)
  {
    _objects[i] = [_objects[i] copy]; // deepen the copy
  }
  
  return self;
}


//// Destructor

//
// Free the array, not the stored objects
//
// @return the object
//

- shallowFree
{
  {
    long i;

    for (i = 0; i < _length; i++)
    {
      _objects[i] = nil;
    }
  }
  
  objc_free(_objects);
  
  [super free];

  return self;
}

//
// (Deep) free the array (incl. the objects)
//
// @return the object
//

- free
{
  long i;

  for (i = 0; i <_length; i++)
  {
    if (_objects[i] != nil)
      [_objects[i] free];
  }

  [self shallowFree];

  return self;
}


//// Member methods

//
// Return the length of the array
//
// @return the length
//

- (long) length
{
  return _length;
}

//
// Set the length for the array
//
// @param length   the new length 
//
// @return the object
//

- (DArray *) length :(long) length
{
  if (length > _length)
  {
    long i = 0L;
    
    id *origin = _objects;
    
    _objects = (id *) objc_malloc(sizeof(id) * length);

    while (i < _length)
    {
      _objects[i] = origin[i];
      i++;
    }
    while (i < length)
    {
      _objects[i] = nil;
      i++;
    }

    objc_free(origin);

    _length = length;
  }
  else
  {
    WARNING(DW_INVALID_ARG, "length");
  }
  
  return self;
}

//
// Test if an index is valid
//
// @param index   the index to be tested
//
// @return is it valid ?
//

- (BOOL) isValid :(long) index
{
  return ((index >= 0) && (index < _length));
}


//// Main methods

//
// Set an object in the array
//
// @param index    the index in the array
// @param obj      the object to be set
//
// @return the previous object in the array (or nil)
//

- (id) set :(long) index :(id) obj
{
  id prev = nil;
  
  if ((index >= 0) && (index < _length))
  {
    prev = _objects[index];

    _objects[index] = obj;
  }
  else
  {
    WARNING(DW_ARG_OUT_RANGE, "index");
  }
  
  return prev;
}

//
// Get an object from the array
//
// @param index    the index in the array
//
// @return the object in the array (or nil)
//

- (id) get :(long) index
{
  id obj = nil;

  if ((index >= 0) && (index < _length))
  {
    obj = _objects[index];
  }
  else
  {
    WARNING(DW_ARG_OUT_RANGE, "index");
  }
  
  return obj;
}


//// Object location methods

//
// Find the first occurence of an object
//
// @param obj      the object to be found
//
// @return the first occurence of the object (or -1 for not found)
//

- (long) index :(id) obj
{
  long i;

  for (i = 0; i <_length; i++)
  {
    if (_objects[i] == obj)
    {
      return i;
    }
  }

  return -1L;
}

//
// Find the last occurence of an object
//
// @param obj      the object to be found
//
// @return the last occurence of the object (or -1 for not found)
//

- (long) rindex :(id) obj
{
  long i;

  for (i = _length-1; i >= 0; i--)
  {
    if (_objects[i] == obj)
    {
      return i;
    }
  }

  return -1L;
}

//
// Count the number of occurences of an object
//
// @param obj      the object to be counted
//
// @return the number of occurences
//

- (long) count :(id) obj
{
  long i;
  long c = 0L;

  for (i = 0; i <_length; i++)
  {
    if (_objects[i] == obj)
      c++;
  }

  return c;
}

//
// Test if an object is in an array
//
// @param obj      the object to be checked
//
// @return is it in the array ?
//

- (BOOL) has :(id) obj
{
  return ([self index :obj] != -1L);
}

//
// Perform a selector on each object in the array
//
// @param sel      the selector
//
// @return the object
//

- (DArray *) each :(SEL) sel
{
  long i;

  for (i = 0L; i < _length; i++)
  {
    if (_objects[i] != nil)
    {
      [_objects[i] perform :sel];
    }
  }

  return self;
}

@end

/*==========================================================================*/
